package com.xkh.common.data;

import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @author xkh
 * @since 2021/7/4 0004
 */
@Slf4j
public class Handling {
    @Data
    @RequiredArgsConstructor
    static class Item {
        String name;
        int num = 1000;
        @ToString.Exclude
        ReentrantLock lock = new ReentrantLock();
    }

    private List<Item> items() {
        List<Item> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Item item = new Item();
            item.setName("商品" + i);
            list.add(item);
        }
        return list;
    }

    private List<Item> createCart(List<Item> items) {
        return IntStream.rangeClosed(1, 3).mapToObj(i -> ThreadLocalRandom.current().nextInt(items.size())).map(name -> items.get(name)).collect(Collectors.toList());
    }

    @Test
    public void test() throws InterruptedException {
        long begin = System.currentTimeMillis();
        List<Item> items = items();
        long success = IntStream.rangeClosed(1,100).parallel().mapToObj(i-> {
           return test3(createCart(items).stream().sorted(Comparator.comparing(Item :: getName)).collect(Collectors.toList()));
        }).filter(result->result).count();
        log.info("success:{},time:{}",success,System.currentTimeMillis()-begin);
    }


    public boolean test3(List<Item> range){
        //存放所有获得的锁
        List<ReentrantLock> locks = new ArrayList<>();
        for (Item item : range) {
            try {
                if (item.lock.tryLock(10, TimeUnit.SECONDS)) {
                    locks.add(item.lock);
                }else {
                    locks.forEach(ReentrantLock :: unlock);
                    return false;
                }
            } catch (InterruptedException e) {

            }
        }
        try{
            //锁全部拿到之后执行扣减库存业务逻辑
            range.forEach(item -> item.num--);
        }finally {
            locks.forEach(ReentrantLock :: unlock);
        }
        return true;
    }
}
